/*
 * @Author: 0x9DEFA478
 * @Date: 2021-08-07 20:07:01
 * @LastEditTime: 2021-08-21 22:04:56
 * @LastEditors: 0x9DEFA478
 * @Description: 此文件实现了CMSIS-DAP 与 CDC的组合设备
 * QQ:2652450237
 * ============================================================================================================================================
 * 
 * 
 * 
 *                                                                                               ************      ****************************
 *                                                                                             ************      ****************************  
 *                                                                                           ************      ****************************    
 *                                                                                         ************      ****************************      
 *                                                                                       ************      ************                        
 *                                                                                     ************      ************                          
 *                                                                                   ************      ************                            
 *                                                                                 ************      ************                              
 *                                                                               ************      ************                                
 *                                                                             ************      ************                                  
 *                                                                           ************      ************                                    
 *                                                                         ************      ************                                      
 *                                                                       ************      ************                                        
 *                                                                     ************      ************                                          
 *                                                                   ************      ************                                            
 *                                                                 ************      ************                                              
 *                                                               ************      ************                                                
 *                                                             ************      ************                                                  
 *                                                           ************      ************                                                    
 *                                                         ************      ************                                                      
 *                                                       ************      ************                                                        
 *                                                     ************      ************                                                          
 *                                                   ************      ************                                                            
 *                                                 ************      ************                                                              
 *                                               ************      ************                                                                
 *                                             ************      ************                                                                  
 *                                           ************      ************                                                                    
 *                                         ************      ************                                                                      
 *                                       ************      ************                                                                        
 *                                     ************      ************                                                                          
 *                                   ************      ************                                                                            
 *                                 ************      ************                                                                              
 *                               ************      ************                                                                                
 *                             ************      ************                                                                                  
 *                           ************      ************                                                                                    
 *                         ************      ************                                                                                      
 *       ****************************      ************                                                                                        
 *     ****************************      ************                                                                                          
 *   ****************************      ************                                                                                            
 * ****************************      ************                                                                                              
 * 
 * 
 * 
 * ============================================================================================================================================
 * 
 */
#include "usbd_class.h"
#include "usbd_class_if.h"
#include "usbd_ctlreq.h"
#include "usbd_ioreq.h"
#include "usbd_desc.h"




#define vWinusb_CMSIS_DAP_Interface           0U                   //CMSIS_DAP使用的接口
#define vWinusb_CMSIS_DAP_OutEndPoint         0x01U
#define vWinusb_CMSIS_DAP_InEndPoint          0x81U
#define vWinusb_CMSIS_DAP_EndPointPackSize    512U

#define vWinusb_Interface                    1U                    //自定义winusb使用的接口
#define vWinusb_OutEndPoint                  0x02U
#define vWinusb_InEndPoint                   0x82U
#define vWinusb_EndPointPackSize             512U

#define vCDC_Interface_Ctrl                  2U                    //CDC CMD使用的接口
#define vCDC_Interface_Data                  3U                    //CDC DATA使用的接口
#define vCDC_InEndPoint_Ctrl                 0x84U
#define vCDC_InEndPoint_Data                 0x83U
#define vCDC_OutEndPoint_Data                0x03U
#define vCDC_EndPointPackSize_Ctrl           8U
#define vCDC_EndPointPackSize_Data           512U
#define vCDC_CS_INTERFACE                    0x24U
#define vCDC_CS_ENDPOINT                     0x25U



typedef struct{
  void* pdev;

  //发送到主机的状态是否忙碌
  volatile int IsBusy_Transmit;

  //是否为奇数包
  volatile int RecvBufferIsOdd;
  unsigned int RecvBuffer[(vWinusb_CMSIS_DAP_EndPointPackSize*2+3)/4];

  struct{
    void (*RecvCallback)(unsigned char*,int);
  }Callback;

}Class_Winusb_CMSIS_DAP;

typedef struct{
  void* pdev;

  //发送到主机的状态是否忙碌
  volatile int IsBusy_Transmit;

  //是否为奇数包
  volatile int RecvBufferIsOdd;
  unsigned int RecvBuffer[(vWinusb_EndPointPackSize*2+3)/4];

  struct{
    void (*RecvCallback)(unsigned char*,int);
  }Callback;

}Class_Winusb;

typedef struct{
  void* pdev;

  //发送到主机的状态是否忙碌
  volatile int IsBusy_Transmit;
  
  //是否为奇数包
  volatile int RecvBufferIsOdd;
  unsigned int RecvBuffer[(vCDC_EndPointPackSize_Data*2+3)/4];

  struct{
    void (*RecvCallback)(unsigned char*,int);
  }Callback;

}Class_CDC;



//类结构体 保存各种参数
typedef struct{
  volatile int ConfigurationNum;

  //端点0数据缓存
  unsigned int CtrlEndpointRecvData[16];

  //Setup包数据
  USBD_SetupReqTypedef SETUP;

  //端点0数据接收完成回调
  unsigned char (*volatile CtrlEndpointRecvCallback)(USBD_HandleTypeDef *pdev);

  //配置联合体
  union
  {
    //配置1
    struct{
      
      //CMSIS DAP winusb
      Class_Winusb_CMSIS_DAP Winusb_CMSIS_DAP;

      //自定义winusb
      Class_Winusb Winusb;

      //CDC
      Class_CDC CDC;

    }Configuration1;

    //配置2
    struct{
      void* _keep;
    }Configuration2;

  }Configuration;

}USBD_CLASS;

USBD_CLASS usbd_class={
  .ConfigurationNum=0,
};


static unsigned char ConfigurationNon_SETUP(USBD_HandleTypeDef* pdev, USBD_SetupReqTypedef* req);

static unsigned char Configuration1_Init(USBD_HandleTypeDef *pdev);
static unsigned char Configuration1_DeInit(USBD_HandleTypeDef *pdev);
static unsigned char Configuration1_SETUP(USBD_HandleTypeDef* pdev, USBD_SetupReqTypedef* req);

static unsigned char Configuration2_Init(USBD_HandleTypeDef *pdev);
static unsigned char Configuration2_DeInit(USBD_HandleTypeDef *pdev);
static unsigned char Configuration2_SETUP(USBD_HandleTypeDef* pdev, USBD_SetupReqTypedef* req);




static uint8_t USBD_Class_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t USBD_Class_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t USBD_Class_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
static uint8_t USBD_Class_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_Class_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_Class_EP0_RxReady(USBD_HandleTypeDef *pdev);
static uint8_t USBD_Class_EP0_TxReady(USBD_HandleTypeDef *pdev);
static uint8_t USBD_Class_SOF(USBD_HandleTypeDef *pdev);
static uint8_t USBD_Class_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_Class_IsoOutIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum);

static uint8_t *USBD_Class_GetCfgDesc(uint16_t *length);
static uint8_t *USBD_Class_GetDeviceQualifierDesc(uint16_t *length);


USBD_ClassTypeDef USBD_Class_Driver ={
  USBD_Class_Init,
  USBD_Class_DeInit,
  USBD_Class_Setup,
  USBD_Class_EP0_TxReady,
  USBD_Class_EP0_RxReady,
  USBD_Class_DataIn,
  USBD_Class_DataOut,
  USBD_Class_SOF,
  USBD_Class_IsoINIncomplete,
  USBD_Class_IsoOutIncomplete,
  USBD_Class_GetCfgDesc,
  USBD_Class_GetCfgDesc,
  USBD_Class_GetCfgDesc,
  USBD_Class_GetDeviceQualifierDesc,
};


#define vCfgDesc_Size (137U)
__align(4) static unsigned char CfgDesc[vCfgDesc_Size]={

  // **************** StandardConfigurationDescriptor ****************
  0x09,                                                            /* bLength: Configuation Descriptor size */
  vH_USB_DescType_Configuration,                                   /* bDescriptorType */
  cLittleTo2Bytes(vCfgDesc_Size),                                  /* wTotalLength */
  4U,                                                              /* bNumInterfaces */
  0x01U,                                                           /* bConfigurationValue */
  USBD_IDX_PRODUCT_STR,                                            /* iConfiguration */
  0x80U,                                                           /* bmAttributes */
  50U,                                                             /* MaxPower */
  /* 09 */



  // **************** CMSIS-DAP ****************
  // **************** StandardInterfaceAssociationDescriptor ****************
  8U,                                                              /* bLength */
  vH_USB_DescType_InterfaceAssociation,                            /* bDescriptorType */
  vWinusb_CMSIS_DAP_Interface,                                     /* bFirstInterface */
  0x01U,                                                           /* bInterfaceCount */
  0xFFU,                                                           /* bFunctionClass */
  0x00U,                                                           /* bFunctionSubClass */
  0x00U,                                                           /* bInterfaceProtocol: 该IAD下的InterfaceProtocol */
  USBD_IDX_PRODUCT_STR,                                            /* iFunction */
  /* 17 */

  // **************** InterfaceDescriptor ****************    接口类型: 数据接口
  9U,                                                              /* bLength */
  vH_USB_DescType_Interface,                                       /* bDescriptorType */
  vWinusb_CMSIS_DAP_Interface,                                     /* bInterfaceNumber */
  0x00U,                                                           /* bAlternateSetting */
  0x02U,                                                           /* bNumEndpoints: 该接口使用的端点数量*/
  0xFFU,                                                           /* bInterfaceClass */
  0x00U,                                                           /* bInterfaceSubClass */
  0x00U,                                                           /* bInterfaceProtocol */
  0x00U,                                                           /* iInterface */
  /* 26 */

  // **************** 端点描述符 ****************
  7U,                                                              /* bLength */
  vH_USB_DescType_Endpoint,                                        /* bDescriptorType */
  vWinusb_CMSIS_DAP_OutEndPoint,                                   /* bEndpointAddress */
  0x02U,                                                           /* bmAttributes: 0x02:Bulk */
  cLittleTo2Bytes(vWinusb_CMSIS_DAP_EndPointPackSize),             /* wMaxPacketSize */
  0x00U,                                                           /* bInterval */
  /* 33 */

  // **************** 端点描述符 ****************
  7U,                                                              /* bLength */
  vH_USB_DescType_Endpoint,                                        /* bDescriptorType */
  vWinusb_CMSIS_DAP_InEndPoint,                                    /* bEndpointAddress */
  0x02U,                                                           /* bmAttributes: 0x02:Bulk */
  cLittleTo2Bytes(vWinusb_CMSIS_DAP_EndPointPackSize),             /* wMaxPacketSize */
  0x00U,                                                           /* bInterval */
  /* 40 */




  // **************** 自定义winusb ****************
  // **************** StandardInterfaceAssociationDescriptor ****************
  8U,                                                              /* bLength */
  vH_USB_DescType_InterfaceAssociation,                            /* bDescriptorType */
  vWinusb_Interface,                                               /* bFirstInterface */
  0x01U,                                                           /* bInterfaceCount */
  0xFFU,                                                           /* bFunctionClass */
  0x00U,                                                           /* bFunctionSubClass */
  0x00U,                                                           /* bInterfaceProtocol: 该IAD下的InterfaceProtocol */
  0x67U,                                                           /* iFunction */
  /* 48 */

  // **************** InterfaceDescriptor ****************    接口类型: 数据接口
  9U,                                                              /* bLength */
  vH_USB_DescType_Interface,                                       /* bDescriptorType */
  vWinusb_Interface,                                               /* bInterfaceNumber */
  0x00U,                                                           /* bAlternateSetting */
  0x02U,                                                           /* bNumEndpoints: 该接口使用的端点数量*/
  0xFFU,                                                           /* bInterfaceClass */
  0x00U,                                                           /* bInterfaceSubClass */
  0x00U,                                                           /* bInterfaceProtocol */
  0x00U,                                                           /* iInterface */
  /* 57 */

  // **************** 端点描述符 ****************
  7U,                                                              /* bLength */
  vH_USB_DescType_Endpoint,                                        /* bDescriptorType */
  vWinusb_OutEndPoint,                                             /* bEndpointAddress */
  0x02U,                                                           /* bmAttributes: 0x02:Bulk */
  cLittleTo2Bytes(vWinusb_EndPointPackSize),                       /* wMaxPacketSize */
  0x00U,                                                           /* bInterval */
  /* 64 */

  // **************** 端点描述符 ****************
  7U,                                                              /* bLength */
  vH_USB_DescType_Endpoint,                                        /* bDescriptorType */
  vWinusb_InEndPoint,                                              /* bEndpointAddress */
  0x02U,                                                           /* bmAttributes: 0x02:Bulk */
  cLittleTo2Bytes(vWinusb_EndPointPackSize),                       /* wMaxPacketSize */
  0x00U,                                                           /* bInterval */
  /* 71 */

  
  
  
  // **************** CDC虚拟串口 ****************
  // **************** StandardInterfaceAssociationDescriptor ****************
  8U,                                                              /* bLength */
  vH_USB_DescType_InterfaceAssociation,                            /* bDescriptorType */
  vCDC_Interface_Ctrl,                                             /* bFirstInterface */
  0x02U,                                                           /* bInterfaceCount */
  0x02U,                                                           /* bFunctionClass */
  0x02U,                                                           /* bFunctionSubClass */
  0x01U,                                                           /* bInterfaceProtocol: 该IAD下的InterfaceProtocol */
  0x68U,                                                           /* iFunction */
  /* 79 */
  
  // **************** StandardInterfaceDescriptor ****************    接口类型: CDC-ACM(Communications Class Abstract Control Model Interface Descriptor)
  9U,                                                              /* bLength */
	vH_USB_DescType_Interface,                                       /* bDescriptorType */
	vCDC_Interface_Ctrl,                                             /* bInterfaceNumber */
	0x00U,                                                           /* bAlternateSetting */
	0x01U,                                                           /* bNumEndpoints: 该接口使用的端点数量 */
	0x02U,                                                           /* bInterfaceClass */
	0x02U,                                                           /* bInterfaceSubClass */
	0x01U,                                                           /* bInterfaceProtocol */
	0x68U,                                                           /* iInterface: */
	/* 88 */

  // **************** HeaderFunctionalDescriptor ****************
	5U,                                                              /* bLength: Endpoint Descriptor size */
	vCDC_CS_INTERFACE,                                               /* bDescriptorType */
	0x00U,                                                           /* bDescriptorSubtype: Header Func Desc */
	cLittleTo2Bytes(0x0110U),                                        /* bcdCDC: spec release number */
	/* 93 */

  // **************** CallManagementFunctionalDescriptor ****************
	5U,                                                              /* bFunctionLength */
	vCDC_CS_INTERFACE,                                               /* bDescriptorType: CS_INTERFACE */
	0x01U,                                                           /* bDescriptorSubtype: Call Management Func Desc */
	0x00U,                                                           /* bmCapabilities: D0+D1 */
	vCDC_Interface_Data,                                             /* bDataInterface */
	/* 98 */

  // **************** ACMFunctionalDescriptor ****************
	4U,                                                              /* bFunctionLength */
	vCDC_CS_INTERFACE,                                               /* bDescriptorType: CS_INTERFACE */
	0x02U,                                                           /* bDescriptorSubtype: Abstract Control Management desc */
	0x02U,                                                           /* bmCapabilities */
	/* 102 */

  // **************** UnionFunctionalDescriptor ****************
	5U,                                                              /* bFunctionLength */
	vCDC_CS_INTERFACE,                                               /* bDescriptorType: CS_INTERFACE */
	0x06U,                                                           /* bDescriptorSubtype */
	vCDC_Interface_Ctrl,                                             /* bControlInterface */
	vCDC_Interface_Data,                                             /* bSubordinateInterface0 */
	/* 107 */
	
  // **************** 端点描述符 ****************
	7U,                                                              /* bLength */
	vH_USB_DescType_Endpoint,                                        /* bDescriptorType */
	vCDC_InEndPoint_Ctrl,                                            /* bEndpointAddress */
	0x03U,                                                           /* bmAttributes: 0x03:Interrupt */
	cLittleTo2Bytes(vCDC_EndPointPackSize_Ctrl),                     /* wMaxPacketSize */
	0x10U,                                                           /* bInterval */
	/* 114 */

  // **************** StandardInterfaceDescriptor ****************    接口类型: CDC数据类
	9U,                                                              /* bLength */
	vH_USB_DescType_Interface,                                       /* bDescriptorType */
	vCDC_Interface_Data,                                             /* bInterfaceNumber */
	0x00U,                                                           /* bAlternateSetting */
	0x02U,                                                           /* bNumEndpoints */
	0x0AU,                                                           /* bInterfaceClass */
	0x00U,                                                           /* bInterfaceSubClass */
	0x00U,                                                           /* bInterfaceProtocol */
	0x68U,                                                           /* iInterface: */
	/* 123 */

  // **************** 端点描述符 ****************
	7U,                                                              /* bLength */
	vH_USB_DescType_Endpoint,                                        /* bDescriptorType */
	vCDC_OutEndPoint_Data,                                           /* bEndpointAddress */
	0x02U,                                                           /* bmAttributes: 0x02:Bulk */
	cLittleTo2Bytes(vCDC_EndPointPackSize_Data),                     /* wMaxPacketSize */
	0x00U,                                                           /* bInterval */
	/* 130 */

  // **************** 端点描述符 ****************
	7U,                                                              /* bLength */
	vH_USB_DescType_Endpoint,                                        /* bDescriptorType */
	vCDC_InEndPoint_Data,                                            /* bEndpointAddress */
	0x02U,                                                           /* bmAttributes: 0x02:Bulk */
	cLittleTo2Bytes(vCDC_EndPointPackSize_Data),                     /* wMaxPacketSize */
	0x00U,                                                           /* bInterval */
	/* 137 */

};


__align(4) static unsigned char DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC]={
  USB_LEN_DEV_QUALIFIER_DESC,                                      /* bLength */
  USB_DESC_TYPE_DEVICE_QUALIFIER,                                  /* bDescriptorType */
#if ((USBD_LPM_ENABLED == 1) || (USBD_CLASS_BOS_ENABLED == 1))
  cLittleTo2Bytes(0x0201U),                                        /* bcdUSB */     /* changed to USB version 2.01 in order to support BOS Desc */
#else
  cLittleTo2Bytes(0x0200U),                                        /* bcdUSB */
#endif
  0xEF,                                                            /* bDeviceClass */
  0x02,                                                            /* bDeviceSubClass */
  0x01,                                                            /* bDeviceProtocol */
  0x40,                                                            /* bMaxPacketSize0 */
  0x01,                                                            /* bNumConfigurations */
  0x00,                                                            /* bReserved */
};


//============================================================================================================================================
//
// USBD_ClassTypeDef需要的方法
//
//============================================================================================================================================

/**
 * @brief 初始化类配置
 * @param pdev USBD句柄
 * @param cfgidx 配置编号
 * @return status
 */
static uint8_t USBD_Class_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx){

  switch(cfgidx){
    case 1:
      return Configuration1_Init(pdev);
    case 2:
      return Configuration2_Init(pdev);
    default:
      while(1);
  }

  return (uint8_t)USBD_FAIL;
}

static uint8_t USBD_Class_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx){
  switch(cfgidx){
    case 1:
      return Configuration1_DeInit(pdev);
    case 2:
      return Configuration2_DeInit(pdev);
    default:
      while(1);
  }
}

//接收到SETUP包回调
static uint8_t USBD_Class_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req){
  USBD_StatusTypeDef ret;

  switch(usbd_class.ConfigurationNum){
    case 1:
      return Configuration1_SETUP(pdev,req);
    case 2:
      return Configuration2_SETUP(pdev,req);
    default:
      return ConfigurationNon_SETUP(pdev,req);
  }

  USBD_CtlError(pdev,req);
  ret=USBD_FAIL;
  return (uint8_t)ret;
}

//非零端点数据发送完成回调
static uint8_t USBD_Class_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum){

  if(usbd_class.ConfigurationNum==1){
    switch(epnum&0x0FU){
      case vWinusb_CMSIS_DAP_InEndPoint&0x0FU:
        usbd_class.Configuration.Configuration1.Winusb_CMSIS_DAP.IsBusy_Transmit=0;
        usbd_class_Winusb_CMSIS_DAP_SendDoneCallback();
        break;
      case vWinusb_InEndPoint&0x0FU:
        usbd_class.Configuration.Configuration1.Winusb.IsBusy_Transmit=0;
        usbd_class_Winusb_SendDoneCallback();
        break;
      case vCDC_InEndPoint_Data&0x0FU:
        usbd_class.Configuration.Configuration1.CDC.IsBusy_Transmit=0;
        usbd_class_CDC_SendDoneCallback();
        break;
      case vCDC_InEndPoint_Ctrl&0x0FU:
        break;
      default:
        break;
    }
  }

  return (uint8_t)USBD_OK;
}

//非零端点数据接收完成回调
static uint8_t USBD_Class_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum){
  unsigned int RxLength;

  union{
    Class_Winusb_CMSIS_DAP* winusb_cmsis_dap;
    Class_Winusb* winusb;
    Class_CDC* cdc;
  }this_class;
  

  if(usbd_class.ConfigurationNum==1){

    RxLength=USBD_LL_GetRxDataSize(pdev,epnum);

    switch(epnum&0x0FU){
      case vWinusb_CMSIS_DAP_OutEndPoint&0x0FU:

        this_class.winusb_cmsis_dap=&usbd_class.Configuration.Configuration1.Winusb_CMSIS_DAP;

        if(this_class.winusb_cmsis_dap->RecvBufferIsOdd==0){
          USBD_LL_PrepareReceive(pdev,vWinusb_CMSIS_DAP_OutEndPoint,(unsigned char*)&this_class.winusb_cmsis_dap->RecvBuffer[(vWinusb_CMSIS_DAP_EndPointPackSize+3)/4],vWinusb_CMSIS_DAP_EndPointPackSize);
          this_class.winusb_cmsis_dap->Callback.RecvCallback((unsigned char*)&this_class.winusb_cmsis_dap->RecvBuffer[0],RxLength);
          this_class.winusb_cmsis_dap->RecvBufferIsOdd=-1;
        }else{
          USBD_LL_PrepareReceive(pdev,vWinusb_CMSIS_DAP_OutEndPoint,(unsigned char*)&this_class.winusb_cmsis_dap->RecvBuffer[0],vWinusb_CMSIS_DAP_EndPointPackSize);
          this_class.winusb_cmsis_dap->Callback.RecvCallback((unsigned char*)&this_class.winusb_cmsis_dap->RecvBuffer[(vWinusb_CMSIS_DAP_EndPointPackSize+3)/4],RxLength);
          this_class.winusb_cmsis_dap->RecvBufferIsOdd=0;
        }
        
        break;

      case vWinusb_OutEndPoint&0x0FU:

        this_class.winusb=&usbd_class.Configuration.Configuration1.Winusb;

        if(this_class.winusb->RecvBufferIsOdd==0){
          USBD_LL_PrepareReceive(pdev,vWinusb_OutEndPoint,(unsigned char*)&this_class.winusb->RecvBuffer[(vWinusb_EndPointPackSize+3)/4],vWinusb_EndPointPackSize);
          this_class.winusb->Callback.RecvCallback((unsigned char*)&this_class.winusb->RecvBuffer[0],RxLength);
          this_class.winusb->RecvBufferIsOdd=-1;
        }else{
          USBD_LL_PrepareReceive(pdev,vWinusb_OutEndPoint,(unsigned char*)&this_class.winusb->RecvBuffer[0],vWinusb_EndPointPackSize);
          this_class.winusb->Callback.RecvCallback((unsigned char*)&this_class.winusb->RecvBuffer[(vWinusb_EndPointPackSize+3)/4],RxLength);
          this_class.winusb->RecvBufferIsOdd=0;
        }

        break;

      case vCDC_OutEndPoint_Data&0x0FU:
      
        this_class.cdc=&usbd_class.Configuration.Configuration1.CDC;

        if(this_class.cdc->RecvBufferIsOdd==0){
          USBD_LL_PrepareReceive(pdev,vCDC_OutEndPoint_Data,(unsigned char*)&this_class.cdc->RecvBuffer[(vCDC_EndPointPackSize_Data+3)/4],vCDC_EndPointPackSize_Data);
          this_class.cdc->Callback.RecvCallback((unsigned char*)&this_class.cdc->RecvBuffer[0],RxLength);
          this_class.cdc->RecvBufferIsOdd=-1;
        }else{
          USBD_LL_PrepareReceive(pdev,vCDC_OutEndPoint_Data,(unsigned char*)&this_class.cdc->RecvBuffer[0],vCDC_EndPointPackSize_Data);
          this_class.cdc->Callback.RecvCallback((unsigned char*)&this_class.cdc->RecvBuffer[(vCDC_EndPointPackSize_Data+3)/4],RxLength);
          this_class.cdc->RecvBufferIsOdd=0;
        }

        break;
      default:
        break;
    }
  }

  return (uint8_t)USBD_OK;
}

//端点0数据接收完成回调
static uint8_t USBD_Class_EP0_RxReady(USBD_HandleTypeDef *pdev){
  if(usbd_class.ConfigurationNum==1){
    if(usbd_class.CtrlEndpointRecvCallback!=NULL){
      usbd_class.CtrlEndpointRecvCallback(pdev);
    }
  }
  return (uint8_t)USBD_OK;
}

//端点0数据发送完成回调
static uint8_t USBD_Class_EP0_TxReady(USBD_HandleTypeDef *pdev){
  if(usbd_class.ConfigurationNum==1){
  }
  return (uint8_t)USBD_OK;
}

//SOF中断回调
static uint8_t USBD_Class_SOF(USBD_HandleTypeDef *pdev){
  if(usbd_class.ConfigurationNum==1){
  }
  return (uint8_t)USBD_OK;
}

//ISO发送未完成回调(在一帧结束后 数据仍未传输完成)
static uint8_t USBD_Class_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum){
  if(usbd_class.ConfigurationNum==1){
  }
  return (uint8_t)USBD_OK;
}

//ISO接收未完成回调(在一帧结束后 数据仍未传输完成)
static uint8_t USBD_Class_IsoOutIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum){
  if(usbd_class.ConfigurationNum==1){
  }
  return (uint8_t)USBD_OK;
}


static uint8_t *USBD_Class_GetCfgDesc(uint16_t *length){
  
  *length=vCfgDesc_Size;
  return CfgDesc;
}

static uint8_t *USBD_Class_GetDeviceQualifierDesc(uint16_t *length){
  *length=USB_LEN_DEV_QUALIFIER_DESC;
  return DeviceQualifierDesc;
}





//============================================================================================================================================
//
// 用户方法
//
//============================================================================================================================================


static USBD_EndpointTypeDef* OpenEndPoint(USBD_HandleTypeDef* pdev,uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps){
  USBD_EndpointTypeDef* r;

  USBD_LL_OpenEP(pdev,ep_addr,ep_type,ep_mps);
  if((ep_addr&0x80U)==0x80U){
    r=&pdev->ep_in[ep_addr & 0xFU];
  }else{
    r=&pdev->ep_out[ep_addr & 0xFU];
  }
  r->is_used=1U;
  return r;
}

static USBD_EndpointTypeDef* CloseEndPoint(USBD_HandleTypeDef* pdev,uint8_t ep_addr){
  USBD_EndpointTypeDef* r;

  USBD_LL_CloseEP(pdev,ep_addr);
  if((ep_addr&0x80U)==0x80U){
    r=&pdev->ep_in[ep_addr & 0xFU];
  }else{
    r=&pdev->ep_out[ep_addr & 0xFU];
  }
  r->is_used=0U;
  r->bInterval=0U;
  return r;
}


//CDC类控制节点接收回调
static unsigned char CDC_CtrlEndpointRecvCallback(USBD_HandleTypeDef *pdev){
  
  usbd_class_CDC_Ctrl_Callback(&usbd_class.SETUP,(unsigned char*)usbd_class.CtrlEndpointRecvData,usbd_class.SETUP.wLength);

  return (unsigned char)USBD_OK;
}

/**
 * @brief CDC请求解析
 * @param pdev usb句柄
 * @param req 请求
 * @return noEdit
 */
static unsigned char CDC_SetupReqDecode(USBD_HandleTypeDef* pdev,USBD_SetupReqTypedef* req){

  if(req->wLength==0){
    usbd_class_CDC_Ctrl_Callback(req,NULL,0);
  }else{
    if((req->bmRequest&0x80)==0x80){
      usbd_class_CDC_Ctrl_Callback(req,(unsigned char*)usbd_class.CtrlEndpointRecvData,req->wLength);
      USBD_CtlSendData(pdev,(unsigned char*)usbd_class.CtrlEndpointRecvData,req->wLength);
    }else{
      usbd_class.CtrlEndpointRecvCallback=CDC_CtrlEndpointRecvCallback;
      usbd_class.SETUP=*req;
      USBD_CtlPrepareRx(pdev,(unsigned char*)usbd_class.CtrlEndpointRecvData,req->wLength);
    }
  }

  // //如果没有做出响应 必须调用这个
  // USBD_CtlError(pdev,req);
  // return (unsigned char)USBD_FAIL;
  return (unsigned char)USBD_OK;
}







/**
 * @brief 配置 non Setup包处理
 * @param pdev usb句柄
 * @param req 请求
 * @return status
 */
static unsigned char ConfigurationNon_SETUP(USBD_HandleTypeDef* pdev,USBD_SetupReqTypedef* req){
  unsigned char* ucp;
  unsigned int Length;

  switch(req->bmRequest&USB_REQ_TYPE_MASK){

    case USB_REQ_TYPE_CLASS:
      //类请求

      switch(req->bmRequest&USB_REQ_RECIPIENT_MASK){
        
        case USB_REQ_RECIPIENT_DEVICE:
          //器件请求
          break;

        case USB_REQ_RECIPIENT_INTERFACE:
          //接口请求
          break;

        case USB_REQ_RECIPIENT_ENDPOINT:
          //端点请求
          break;

        default:
          break;
      }
      break;

    case USB_REQ_TYPE_VENDOR:
      //厂商请求

      switch(req->bmRequest&USB_REQ_RECIPIENT_MASK){
        
        case USB_REQ_RECIPIENT_DEVICE:
          //器件请求

          if(req->bRequest==USB_MS_VendorCode){
            switch(req->wIndex){
              case 0x0007U:
                if((req->bmRequest&0x80U)==0x80U){
                  ucp=USBD_Class_MS_OS_20_DescriptorSet(pdev->dev_speed,&Length);
                  Length=MIN(Length,req->wLength);
                  if(Length!=0){
                    USBD_CtlSendData(pdev,ucp,Length);
                  }
                  return USBD_OK;
                }
                break;
              case 0x0008U:
                break;
              default:
                break;
            }
          }

          break;

        case USB_REQ_RECIPIENT_INTERFACE:
          //接口请求
          break;

        case USB_REQ_RECIPIENT_ENDPOINT:
          //端点请求
          break;

        default:
          break;
      }
      break;

    case USB_REQ_TYPE_STANDARD:
      //标准请求

      switch(req->bmRequest&USB_REQ_RECIPIENT_MASK){

        case USB_REQ_RECIPIENT_DEVICE:
          //器件请求
          break;

        case USB_REQ_RECIPIENT_INTERFACE:
          //接口请求
          break;

        case USB_REQ_RECIPIENT_ENDPOINT:
          //端点请求
          break;

        default:
          break;
      }
      break;

    default:
      break;
  }

  //如果没有做出响应 必须调用这个
  USBD_CtlError(pdev,req);
  return (unsigned char)USBD_OK;
}

/**
 * @brief 配置1初始化
 * @param pdev usb句柄
 * @return status
 */
static unsigned char Configuration1_Init(USBD_HandleTypeDef* pdev){
  Class_Winusb_CMSIS_DAP* class_winusb_cmsis_dap;
  Class_Winusb* class_winusb;
  Class_CDC* class_cdc;
  USBD_EndpointTypeDef* endpoint;

  //类全局初始化
  usbd_class.ConfigurationNum=1;
  usbd_class.CtrlEndpointRecvCallback=NULL;

  //各个类初始化
  class_winusb_cmsis_dap=&usbd_class.Configuration.Configuration1.Winusb_CMSIS_DAP;
  class_winusb_cmsis_dap->pdev=pdev;
  class_winusb_cmsis_dap->IsBusy_Transmit=0;
  class_winusb_cmsis_dap->RecvBufferIsOdd=0;
  class_winusb_cmsis_dap->Callback.RecvCallback=usbd_class_Winusb_CMSIS_DAP_RecvCallback;

  class_winusb=&usbd_class.Configuration.Configuration1.Winusb;
  class_winusb->pdev=pdev;
  class_winusb->IsBusy_Transmit=0;
  class_winusb->RecvBufferIsOdd=0;
  class_winusb->Callback.RecvCallback=usbd_class_Winusb_RecvCallback;
  
  class_cdc=&usbd_class.Configuration.Configuration1.CDC;
  class_cdc->pdev=pdev;
  class_cdc->IsBusy_Transmit=0;
  class_cdc->RecvBufferIsOdd=0;
  class_cdc->Callback.RecvCallback=usbd_class_CDC_RecvCallback;
  

  //端点初始化
  endpoint=OpenEndPoint(pdev,vWinusb_CMSIS_DAP_OutEndPoint,USBD_EP_TYPE_BULK,vWinusb_CMSIS_DAP_EndPointPackSize);
  endpoint->bInterval=0;
  endpoint=OpenEndPoint(pdev,vWinusb_CMSIS_DAP_InEndPoint,USBD_EP_TYPE_BULK,vWinusb_CMSIS_DAP_EndPointPackSize);
  endpoint->bInterval=0;

  endpoint=OpenEndPoint(pdev,vWinusb_OutEndPoint,USBD_EP_TYPE_BULK,vWinusb_EndPointPackSize);
  endpoint->bInterval=0;
  endpoint=OpenEndPoint(pdev,vWinusb_InEndPoint,USBD_EP_TYPE_BULK,vWinusb_EndPointPackSize);
  endpoint->bInterval=0;

  endpoint=OpenEndPoint(pdev,vCDC_OutEndPoint_Data,USBD_EP_TYPE_BULK,vCDC_EndPointPackSize_Data);
  endpoint->bInterval=0;
  endpoint=OpenEndPoint(pdev,vCDC_InEndPoint_Data,USBD_EP_TYPE_BULK,vCDC_EndPointPackSize_Data);
  endpoint->bInterval=0;
  endpoint=OpenEndPoint(pdev,vCDC_InEndPoint_Ctrl,USBD_EP_TYPE_INTR,vCDC_EndPointPackSize_Ctrl);
  endpoint->bInterval=0x10U;


  //Out端点预接收
  USBD_LL_PrepareReceive(pdev,vWinusb_CMSIS_DAP_OutEndPoint,(unsigned char*)&class_winusb_cmsis_dap->RecvBuffer[0],vWinusb_CMSIS_DAP_EndPointPackSize);

  USBD_LL_PrepareReceive(pdev,vWinusb_OutEndPoint,(unsigned char*)&class_winusb->RecvBuffer[0],vWinusb_EndPointPackSize);

  USBD_LL_PrepareReceive(pdev,vCDC_OutEndPoint_Data,(unsigned char*)&class_cdc->RecvBuffer[0],vCDC_EndPointPackSize_Data);


  usbd_class_ConnectCallback(1);

  return (unsigned char)USBD_OK;
} 

/**
 * @brief 配置1反初始化
 * @param pdev usb句柄
 * @return status
 */
static unsigned char Configuration1_DeInit(USBD_HandleTypeDef* pdev){

  usbd_class.ConfigurationNum=0;

  usbd_class_DisConnectCallback(1);

  CloseEndPoint(pdev,vWinusb_CMSIS_DAP_OutEndPoint);
  CloseEndPoint(pdev,vWinusb_CMSIS_DAP_InEndPoint);
  
  CloseEndPoint(pdev,vWinusb_OutEndPoint);
  CloseEndPoint(pdev,vWinusb_InEndPoint);

  CloseEndPoint(pdev,vCDC_OutEndPoint_Data);
  CloseEndPoint(pdev,vCDC_InEndPoint_Data);
  CloseEndPoint(pdev,vCDC_InEndPoint_Ctrl);

  return (unsigned char)USBD_OK;
}

/**
 * @brief 配置1 Setup包处理
 * @param pdev usb句柄
 * @param req 请求
 * @return status
 */
static unsigned char Configuration1_SETUP(USBD_HandleTypeDef* pdev,USBD_SetupReqTypedef* req){
  unsigned char* ucp;
  unsigned int Length;

  switch(req->bmRequest&USB_REQ_TYPE_MASK){

    case USB_REQ_TYPE_CLASS:
      //类请求

      switch(req->bmRequest&USB_REQ_RECIPIENT_MASK){
        
        case USB_REQ_RECIPIENT_DEVICE:
          //器件请求
          break;

        case USB_REQ_RECIPIENT_INTERFACE:
          //接口请求

          switch(req->wIndex&0x0FU){
            case vCDC_Interface_Ctrl:
            case vCDC_Interface_Data:
              return CDC_SetupReqDecode(pdev,req);
            default:
              break;
          }

          break;

        case USB_REQ_RECIPIENT_ENDPOINT:
          //端点请求
          break;

        default:
          break;
      }
      break;

    case USB_REQ_TYPE_VENDOR:
      //厂商请求

      switch(req->bmRequest&USB_REQ_RECIPIENT_MASK){
        
        case USB_REQ_RECIPIENT_DEVICE:
          //器件请求

          if(req->bRequest==USB_MS_VendorCode){
            switch(req->wIndex){
              case 0x0007U:
                if((req->bmRequest&0x80U)==0x80U){
                  ucp=USBD_Class_MS_OS_20_DescriptorSet(pdev->dev_speed,&Length);
                  Length=MIN(Length,req->wLength);
                  if(Length!=0){
                    USBD_CtlSendData(pdev,ucp,Length);
                  }
                  return USBD_OK;
                }
                break;
              case 0x0008U:
                break;
              default:
                break;
            }
          }

          break;

        case USB_REQ_RECIPIENT_INTERFACE:
          //接口请求
          break;

        case USB_REQ_RECIPIENT_ENDPOINT:
          //端点请求
          break;

        default:
          break;
      }
      break;

    case USB_REQ_TYPE_STANDARD:
      //标准请求

      switch(req->bmRequest&USB_REQ_RECIPIENT_MASK){

        case USB_REQ_RECIPIENT_DEVICE:
          //器件请求
          break;

        case USB_REQ_RECIPIENT_INTERFACE:
          //接口请求
          break;

        case USB_REQ_RECIPIENT_ENDPOINT:
          //端点请求
          break;

        default:
          break;
      }
      break;

    default:
      break;
  }

  //如果没有做出响应 必须调用这个
  USBD_CtlError(pdev,req);
  return (unsigned char)USBD_OK;
}



/**
 * @brief 配置2初始化
 * @param pdev usb句柄
 * @return status
 */
static unsigned char Configuration2_Init(USBD_HandleTypeDef* pdev){
  return (unsigned char)USBD_FAIL;
}

/**
 * @brief 配置2反初始化
 * @param pdev usb句柄
 * @return status
 */
static unsigned char Configuration2_DeInit(USBD_HandleTypeDef* pdev){
  return (unsigned char)USBD_FAIL;
}

/**
 * @brief 配置2 Setup包处理
 * @param pdev usb句柄
 * @param req 请求
 * @return status
 */
static unsigned char Configuration2_SETUP(USBD_HandleTypeDef* pdev, USBD_SetupReqTypedef* req){
  USBD_CtlError(pdev,req);
  return (unsigned char)USBD_FAIL;
}




//============================================================================================================================================
//
// 提供的外部方法
//
//============================================================================================================================================

/**
 * @brief 获取配置号
 * @return 配置号 如果为0代表未设置配置
 */
int usbd_class_GetConfigurationNum_m(){
  return usbd_class.ConfigurationNum;
}

/**
 * @brief 发送数据 
 * @param pdev usb句柄
 * @param Data 要发送的数据 此地址要4字节对齐
 * @param Length 发送的数据长度
 * @return 0:成功 其他:失败
 */
int usbd_class_Winusb_CMSIS_DAP_Send_m(void* pdev,unsigned char* Data,int Length){

  switch(usbd_class.ConfigurationNum){
    case 1:
      if(usbd_class.Configuration.Configuration1.Winusb_CMSIS_DAP.IsBusy_Transmit==0){
        usbd_class.Configuration.Configuration1.Winusb_CMSIS_DAP.IsBusy_Transmit=-1;
        USBD_LL_Transmit(pdev,vWinusb_CMSIS_DAP_InEndPoint,Data,Length);
        return 0;
      }
      return -1;
    case 2:
      break;
    default:
      break;
  }

  return -2;
}

/**
 * @brief 检查发送是否忙碌
 * @param pdev usb句柄
 * @return 0:空闲 其他:忙碌
 */
int usbd_class_Winusb_CMSIS_DAP_IsBusy_m(void* pdev){
  switch(usbd_class.ConfigurationNum){
    case 1:
      if(usbd_class.Configuration.Configuration1.Winusb_CMSIS_DAP.IsBusy_Transmit==0){
        return 0;
      }
      return -1;
    case 2:
      break;
    default:
      break;
  }

  return -2;
}

/**
 * @brief 发送数据 
 * @param pdev usb句柄
 * @param Data 要发送的数据 此地址要4字节对齐
 * @param Length 发送的数据长度
 * @return 0:成功 其他:失败
 */
int usbd_class_Winusb_Send_m(void* pdev,unsigned char* Data,int Length){

  switch(usbd_class.ConfigurationNum){
    case 1:
      if(usbd_class.Configuration.Configuration1.Winusb.IsBusy_Transmit==0){
        usbd_class.Configuration.Configuration1.Winusb.IsBusy_Transmit=-1;
        USBD_LL_Transmit(pdev,vWinusb_InEndPoint,Data,Length);
        return 0;
      }
      return -1;
    case 2:
      break;
    default:
      break;
  }

  return -2;
}

/**
 * @brief 检查发送是否忙碌
 * @param pdev usb句柄
 * @return 0:空闲 其他:忙碌
 */
int usbd_class_Winusb_IsBusy_m(void* pdev){
  switch(usbd_class.ConfigurationNum){
    case 1:
      if(usbd_class.Configuration.Configuration1.Winusb.IsBusy_Transmit==0){
        return 0;
      }
      return -1;
    case 2:
      break;
    default:
      break;
  }

  return -2;
}

/**
 * @brief 发送数据 
 * @param pdev usb句柄
 * @param Data 要发送的数据 此地址要4字节对齐
 * @param Length 发送的数据长度
 * @return 0:成功 其他:失败
 */
int usbd_class_CDC_Send_m(void* pdev,unsigned char* Data,int Length){

  switch(usbd_class.ConfigurationNum){
    case 1:
      if(usbd_class.Configuration.Configuration1.CDC.IsBusy_Transmit==0){
        usbd_class.Configuration.Configuration1.CDC.IsBusy_Transmit=-1;
        USBD_LL_Transmit(pdev,vCDC_InEndPoint_Data,Data,Length);
        return 0;
      }
      return -1;
    case 2:
      break;
    default:
      break;
  }

  return -2;
}

/**
 * @brief 检查发送是否忙碌
 * @param pdev usb句柄
 * @return 0:空闲 其他:忙碌
 */
int usbd_class_CDC_IsBusy_m(void* pdev){
  switch(usbd_class.ConfigurationNum){
    case 1:
      if(usbd_class.Configuration.Configuration1.CDC.IsBusy_Transmit==0){
        return 0;
      }
      return -1;
    case 2:
      break;
    default:
      break;
  }

  return -2;
}
